package com.mai4j.maiadmin.setup.project;

import com.github.arturopala.gitignore.GitIgnore;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.AbstractFileFilter;
import org.apache.commons.io.filefilter.FileFilterUtils;
import picocli.CommandLine;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.*;

/**
 * 微信公众号请关注: 开源螺丝钉
 * <br>
 * 码云请关注: <a href="https://gitee.com/xiyoufang">https://gitee.com/xiyoufang</a>
 * <br>
 * 哔哩哔哩请关注: <a href="https://space.bilibili.com/438927834">https://space.bilibili.com/438927834</a>
 *
 * @author xiyoufang
 */
@CommandLine.Command(name = "new", description = "新建一个项目")
@Slf4j
public class New implements Callable<Integer> {
    /**
     * groupId
     */
    @CommandLine.Option(names = {"-g", "--group"}, description = "groupId", required = true, interactive = true, echo = true)
    private String groupId;
    /**
     * artifactId
     */
    @CommandLine.Option(names = {"-a", "--artifact"}, description = "artifactId", required = true, interactive = true, echo = true)
    private String artifactId;

    /**
     * dir
     */
    @CommandLine.Option(names = {"-d", "--dir"}, description = "dir", required = true, interactive = true, echo = true)
    private String dir;
    /**
     * 线程池
     */
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
            4,
            8,
            8,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(16),
            new ThreadPoolExecutor.CallerRunsPolicy());

    @Override
    public Integer call() {
        try {
            long s = System.currentTimeMillis();
            File baseDir = new File(dir);
            if (baseDir.exists() && !FileUtils.isEmptyDirectory(baseDir)) {
                System.err.println("目录不为空:" + baseDir.getCanonicalPath());
                return -1;
            }
            FileUtils.forceMkdir(baseDir);
            System.out.println("目录已创建: " + baseDir.getCanonicalPath());
            File srcDir = new File("../");
            Collection<File> gitignoreFiles = FileUtils.listFiles(srcDir, FileFilterUtils.nameFileFilter(".gitignore"), FileFilterUtils.trueFileFilter());
            Map<String, GitIgnore> gitIgnoreMap = new HashMap<>();
            for (File gitignoreFile : gitignoreFiles) {
                gitIgnoreMap.put(getPath(gitignoreFile), GitIgnore.parse(FileUtils.readFileToString(gitignoreFile, StandardCharsets.UTF_8)));
            }
            Collection<File> files = FileUtils.listFiles(srcDir, new AbstractFileFilter() {
                @Override
                public boolean accept(File file) {
                    return isAllowed(gitIgnoreMap, file);
                }
            }, new AbstractFileFilter() {
                @Override
                public boolean accept(final File file) {
                    return isAllowed(gitIgnoreMap, file)
                            && !baseDir.equals(file)
                            && !Objects.equals(file.getName(), ".git");
                }
            });
            int size = files.size();
            CountDownLatch c = new CountDownLatch(size);
            files.forEach(file -> {
                // 过滤后的文件
                executor.execute(() -> {
                    String fullName = getFullName(file).substring("../".length());
                    String newFullName = fullName.replace("com/mai4j/maiadmin", groupId.replace(".", "/"));
                    try {
                        File destFile = new File(dir, newFullName);
                        FileUtils.copyFile(file, destFile);
                        String extension = FilenameUtils.getExtension(destFile.getName()).toLowerCase();
                        switch (extension) {
                            case "xml":
                                String xml = FileUtils.readFileToString(destFile, StandardCharsets.UTF_8);
                                xml = xml.replace("<groupId>com.mai4j.maiadmin</groupId>", "<groupId>" + groupId + "</groupId>")
                                        .replace("<artifactId>mai-admin</artifactId>", "<artifactId>" + artifactId + "</artifactId>");
                                FileUtils.write(destFile, xml, StandardCharsets.UTF_8, false);
                                break;
                            case "java":
                            case "properties":
                            case "factories":
                            case "bat":
                                String java = FileUtils.readFileToString(destFile, StandardCharsets.UTF_8);
                                java = java.replace("com.mai4j.maiadmin", groupId);
                                FileUtils.write(destFile, java, StandardCharsets.UTF_8, false);
                                break;
                            default:
                                if (newFullName.contains("META-INF/services") || newFullName.contains("setup-cli")) {
                                    String f = FileUtils.readFileToString(destFile, StandardCharsets.UTF_8);
                                    f = f.replace("com.mai4j.maiadmin", groupId);
                                    FileUtils.write(destFile, f, StandardCharsets.UTF_8, false);
                                }
                        }
                    } catch (Exception e) {
                        System.err.println("文件处理失败: " + fullName + "-->" + newFullName);
                        System.exit(-1);
                    } finally {
                        c.countDown();
                    }
                });
            });
            c.await();
            System.out.println("处理完成: 耗时" + (System.currentTimeMillis() - s) / 1000f + "s");
        } catch (Exception e) {
            System.err.println("命令执行错误: " + e.getMessage());
            return -1;
        }
        return 0;
    }

    /**
     * 获取路径
     *
     * @param file file
     * @return String
     */
    private static String getPath(File file) {
        return FilenameUtils.separatorsToUnix(FilenameUtils.getPath(file.getPath()));
    }

    /**
     * 获取文件名称
     *
     * @param file file
     * @return full name
     */
    private static String getFullName(File file) {
        return FilenameUtils.separatorsToUnix(file.getPath());
    }

    /**
     * 忽略文件
     *
     * @param ignoreMap ignoreMap
     * @param file      file
     * @return ignored
     */
    private static boolean isAllowed(Map<String, GitIgnore> ignoreMap, File file) {
        for (Map.Entry<String, GitIgnore> ignoreEntry : ignoreMap.entrySet()) {
            String key = ignoreEntry.getKey();
            GitIgnore gitIgnore = ignoreEntry.getValue();
            String fullName = getFullName(file);
            if (FilenameUtils.directoryContains(key, fullName) && gitIgnore.isIgnored(fullName)) {
                System.out.println("Ignored: " + fullName);
                return false;
            }
        }
        return true;
    }
}
